package cn.le.io;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;

/**
 *
 * FileChannel:从文件中读写数据
 * DatagramChannel:能通过UDP读写网络中的数据
 * SocketChannel:能通过TCP读写网络中的数据,在SocketChannel的实现中,SocketChannel只会传输此刻准备好的数据
 *  (可能不足count字节),因此,SocketChannel可能不会将所有的请求数据(count个字节)全部传输到FileChannel中
 * ServerSocketChannel:可以监听新进来的TCP连接,想web服务器那样,对每个新进来的连接都会创建一个SocketChannel    -
 *
 *
 * FileChannel是一个连接到文件的通道,可以通过文件通道来读写文件,FileChannel无法设置为非阻塞模式,
 * 它总运行在阻塞模式下,在使用FileChannel之前,必须先打开它,
 * 有两种方式:使用一个InputStream、outputStream或者RandomAccessFile来获取一个FileChannel实例,但是InputStream和outputStream获取的FileChannel的权限是固定的,
 * InputStream是只读的,outputStream是只写的
 * jdk中新增用FileChannel来的open方法来打开一个文件通道
 */
public class FileChannelDemo {

    public FileChannelDemo() throws IOException {
    }

    public static void main(String[] args) throws IOException{
        //RandomAccessFile可以用来访问安歇保存数据记录的文件,它不属于InputStream和outputStream类系的,
        //它实现了DataInput,DataOutput,DataOutputStream,DataInputStream接口
        //它是一个直接继承Object的独立的类
        // 它可以实现文件定位,移动,判断大小,跳过字节
        //r:代表读,w:表示写,它不支持只写文件
        //在1.4以后它的大部分功能已经被nio的Mappedyteuffer代替了
        RandomAccessFile afile = new RandomAccessFile("E://aaa.txt","rw");
        //设置到此文件开头测量到的文件指针偏移量，在该位置发生下一个读取或写入操作。
        afile.seek(20);
        FileChannel inChannel = afile.getChannel();

        //分配一个48字节的缓冲区
        ByteBuffer buf = ByteBuffer.allocate(1024);
        //将字节读入缓冲区内
        int bytesRead = inChannel.read(buf);
        while (bytesRead != -1)
        {
            System.out.println("read "+bytesRead);
            //反转此缓冲区,首先将限制设置为当前位置,然后将位置设置为0,如果已定义了标记,
            //则丢弃该标记.
            //显示读取数据到buffer,反转后在从buffer读数据,切换读模式
            buf.flip();
            //hasRemaining:告知在当前位置和限制之间是否有元素
            while(buf.hasRemaining())
            {
                System.out.print((char) buf.get());
            }
            buf.clear();//让buffer准备好写入数据,buffer的数据将被清空
            ///buf.compact();:让buffer准备好写入数据,只清空读过的数据,会把未读取的数据拷贝到buffer的起始位置,position设为最后一个未读位置
            bytesRead = inChannel.read(buf);
        }
        afile.close();
        inChannel.close();



        //jdk中新增用FileChannel来的open方法来打开一个文件通道
        Path paht = Paths.get("E://aaa.txt");
        FileChannel fc = FileChannel.open(paht, StandardOpenOption.CREATE,StandardOpenOption.WRITE);

        //如果两个通道中有一个是FileChannel,那么直接可以将数据从一个Channel传输到另一个Channel中
        RandomAccessFile fromFile = new RandomAccessFile("fromFile.txt", "rw");
        FileChannel fromChannel = fromFile.getChannel();

        RandomAccessFile toFile = new RandomAccessFile("toFile.txt", "rw");
        FileChannel toChannel = toFile.getChannel();

        long position =0;
        long count = fromChannel.size();
        //position表示从position处开始写入数据,count表示最多能传输的字节数,如果源通道的剩余的空间小于count,
        //则所传输的字节数要小于请求的字节数

        //将字节从给定的可读取字节通道传输到此通道的文件中
        toChannel.transferFrom(fromChannel,position,count);
        //将字节从此通道的文件传输到给定的可写入字节通道
        toChannel.transferTo(position,count,fromChannel);

        //FileChannel.truncate()方法截取一个文件。截取文件时，文件将中指定长度后面的部分将被删除

        //FileChanenel.force()方法将通道里尚未写入磁盘的数据强制写到磁盘中,出于性能方面的考虑,操作系统会
        //将数据存在内存中,所以无法保证写入到FileChannel里的数据一定及时写到磁盘,
        //forde()方法有一个boolean的类型参数,指明是否同时将文件元素(权限信息等)写到磁盘上
    }
}
